package com.zhijian.medical.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.NumberUtil;
import com.google.common.collect.Lists;
import com.zhijian.medical.config.CommonConfig;
import com.zhijian.medical.dao.local.ExperimentProcessSampleReadyMapper;
import com.zhijian.medical.entity.po.ExperimentProcessSample;
import com.zhijian.medical.entity.po.ExperimentProcessSampleLog;
import com.zhijian.medical.entity.po.ExperimentProcessSampleReady;
import com.zhijian.medical.entity.vo.request.*;
import com.zhijian.medical.entity.vo.response.ExperimentProcessSampleReadyListVo;
import com.zhijian.medical.entity.vo.response.ExperimentProcessSampleReadyVo;
import com.zhijian.medical.entity.vo.response.ExperimentProcessSampleVo;
import com.zhijian.medical.enums.*;
import com.zhijian.medical.holder.CurrentUserHolder;
import com.zhijian.medical.service.ExperimentProcessSampleLogService;
import com.zhijian.medical.service.ExperimentProcessSampleReadyService;
import com.zhijian.medical.service.ExperimentProcessSampleService;
import com.zhijian.medical.util.AssertUtil;
import com.zhijian.medical.util.Page;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Objects;

/**
 * 实验流程-样本准确区详情业务处理层
 *
 * @author HCG
 * @version: 1.0
 * @date 2022-04-17 17:33:53
 */
@Slf4j
@Service
public class ExperimentProcessSampleReadyServiceImpl implements ExperimentProcessSampleReadyService {

    @Autowired
    private ExperimentProcessSampleReadyMapper mapper;

    @Autowired
    private ExperimentProcessSampleService experimentProcessSampleService;

    @Autowired
    private ExperimentProcessSampleLogService experimentProcessSampleLogService;

    @Autowired
    private CommonConfig commonConfig;

    /**
     * 编号
     */
    private static final String number = "FZ-SOP-001-01-%s-%s";

    @Override
    public ExperimentProcessSampleReady selectById(Long id) {
        return mapper.selectByPrimaryKey(id);
    }

    @Override
    public ExperimentProcessSampleReadyVo selectVoById(Long id) {
        ExperimentProcessSampleReadyVo experimentProcessSampleReadyVo = mapper.selectVoById(id);
        if (Objects.isNull(experimentProcessSampleReadyVo)) {
            return null;
        }
        experimentProcessSampleReadyVo.setExperimentProcessSampleList(experimentProcessSampleService.selectList(ExperimentProcessSampleSearchVo.builder()
                .readyId(id)
                .build()));
        return experimentProcessSampleReadyVo;
    }

    @Override
    public ExperimentProcessSampleReadyListVo selectListVoById(Long id) {
        ExperimentProcessSampleReadyListVo experimentProcessSampleReadyListVo = mapper.selectListVoById(id);
        if (Objects.isNull(experimentProcessSampleReadyListVo)) {
            return null;
        }
        List<ExperimentProcessSampleVo> experimentProcessSampleVos = experimentProcessSampleService.selectList(ExperimentProcessSampleSearchVo.builder()
                .readyId(id)
                .build());
        experimentProcessSampleReadyListVo.setExperimentProcessSampleList(experimentProcessSampleVos);
        return experimentProcessSampleReadyListVo;
    }

    @Override
    public void deleteById(Long id) {
        mapper.deleteByPrimaryKey(id);
    }

    @Override
    public void deleteByExperimentProcessId(Long experimentProcessId) {
        mapper.deleteByExperimentProcessId(experimentProcessId);
    }

    @Override
    public Long insert(ExperimentProcessSampleReady experimentProcessSampleReady) {
        Date now = new Date();
        experimentProcessSampleReady.setCreateTime(now);
        experimentProcessSampleReady.setUpdateTime(now);
        experimentProcessSampleReady.setYblkqpcztmqj(StatusEnum.UN_NORMAL.getCode().byteValue());
        experimentProcessSampleReady.setYblkqpmlqpqqjqpj(StatusEnum.UN_NORMAL.getCode().byteValue());
        experimentProcessSampleReady.setYblkqpczywyc(StatusEnum.UN_NORMAL.getCode().byteValue());
        experimentProcessSampleReady.setTlshhrsslqptlhsh(StatusEnum.UN_NORMAL.getCode().byteValue());
        experimentProcessSampleReady.setTlshhrsslqphers(StatusEnum.UN_NORMAL.getCode().byteValue());
        experimentProcessSampleReady.setTlshhrsgczywyc(StatusEnum.UN_NORMAL.getCode().byteValue());
        experimentProcessSampleReady.setLdt(StatusEnum.NORMAL.getCode().byteValue());
        experimentProcessSampleReady.setQpj(StatusEnum.NORMAL.getCode().byteValue());
        experimentProcessSampleReady.setPhy(StatusEnum.NORMAL.getCode().byteValue());
        experimentProcessSampleReady.setRsj(StatusEnum.NORMAL.getCode().byteValue());
        experimentProcessSampleReady.setSyhqjhwhslqpj(StatusEnum.UN_NORMAL.getCode().byteValue());
        experimentProcessSampleReady.setSyhclsyfqw(StatusEnum.UN_NORMAL.getCode().byteValue());
        experimentProcessSampleReady.setSyhjxsyqzwxzs(StatusEnum.UN_NORMAL.getCode().byteValue());
        experimentProcessSampleReady.setDtqrnaybsfzjsyb24hncl(StatusEnum.UN_NORMAL.getCode().byteValue());
        experimentProcessSampleReady.setAzfzsop009dgswzxjxclgcywyc(StatusEnum.UN_NORMAL.getCode().byteValue());
        experimentProcessSampleReady.setLxj(StatusEnum.NORMAL.getCode().byteValue());
        experimentProcessSampleReady.setSjhqjlxj(StatusEnum.UN_NORMAL.getCode().byteValue());
        return mapper.insert(experimentProcessSampleReady) > 0 ? experimentProcessSampleReady.getId() : 0L;
    }

    @Transactional(rollbackFor = Exception.class, value = "localTransactionManager")
    @Override
    public Long insert(ExperimentProcessSampleReadySaveOrUpdateVo experimentProcessSampleReadySaveOrUpdateVo) {
        deleteByExperimentProcessId(experimentProcessSampleReadySaveOrUpdateVo.getExperimentProcessId());
        ExperimentProcessSampleReady experimentProcessSampleReady = new ExperimentProcessSampleReady();
        BeanUtil.copyProperties(experimentProcessSampleReadySaveOrUpdateVo, experimentProcessSampleReady);
        Long id = this.insert(experimentProcessSampleReady);
        //修改样本的肿瘤细胞比例
        experimentProcessSampleReadySaveOrUpdateVo.getSampleList().forEach(s -> {
            ExperimentProcessSample experimentProcessSample = experimentProcessSampleService.selectById(s.getId());
            AssertUtil.notNull(experimentProcessSample, "有样本不存在或者已被删除");
            experimentProcessSampleService.updateByPrimaryKeySelective(ExperimentProcessSample.builder()
                    .id(s.getId())
                    .zlxbbl(s.getZlxbbl())
                    .readyId(id)
                    .build());
        });
        return id;
    }

    @Override
    public boolean update(ExperimentProcessSampleReady experimentProcessSampleReady) {
        Date now = new Date();
        experimentProcessSampleReady.setUpdateTime(now);
        return mapper.updateByPrimaryKey(experimentProcessSampleReady) != 0;
    }

    @Override
    public boolean update(SampleReadySaveOrUpdateVo sampleReadySaveOrUpdateVo) {
        ExperimentProcessSampleReady oldExperimentProcessSampleReady = this.selectById(sampleReadySaveOrUpdateVo.getId());
        AssertUtil.notNull(oldExperimentProcessSampleReady, "此次样本准备不存在或者已被删除");
        ExperimentProcessSampleReady experimentProcessSampleReady = new ExperimentProcessSampleReady();
        BeanUtils.copyProperties(sampleReadySaveOrUpdateVo, experimentProcessSampleReady);
        return this.updateByPrimaryKeySelective(experimentProcessSampleReady);
    }

    @Override
    public boolean updateByPrimaryKeySelective(ExperimentProcessSampleReady record) {
        return mapper.updateByPrimaryKeySelective(record) != 0;
    }

    @Override
    public Integer count(ExperimentProcessSampleReadySearchVo experimentProcessSampleReadySearchVo) {
        return mapper.count(experimentProcessSampleReadySearchVo);
    }

    @Override
    public List<ExperimentProcessSampleReadyListVo> selectList(ExperimentProcessSampleReadySearchVo experimentProcessSampleReadySearchVo) {
        return mapper.selectList(experimentProcessSampleReadySearchVo);
    }

    @Override
    public Page<ExperimentProcessSampleReadyListVo> selectPage(ExperimentProcessSampleReadySearchVo experimentProcessSampleReadySearchVo) {
        //先直接查总数
        int count = count(experimentProcessSampleReadySearchVo);
        //分页
        Page<ExperimentProcessSampleReadyListVo> page = new Page<>(true, count, experimentProcessSampleReadySearchVo.getPageNum(), experimentProcessSampleReadySearchVo.getPageSize());
        experimentProcessSampleReadySearchVo.setStartIndex(page.getStartIndex());
        page.setPage(true);
        page.setTotalCount(count);
        List<ExperimentProcessSampleReadyListVo> responseVos = this.selectList(experimentProcessSampleReadySearchVo);
        page.setData(responseVos);
        return page;
    }

    @Override
    public ExperimentProcessSampleReadyVo selectVoByExperimentProcessId(Long experimentProcessId) {
        ExperimentProcessSampleReadyVo experimentProcessSampleReadyVo = mapper.selectVoByExperimentProcessId(experimentProcessId);
        if (Objects.nonNull(experimentProcessSampleReadyVo)) {
            return experimentProcessSampleReadyVo;
        }
        //如果查不到，就去查这个荧光PCR实验的样本，从样本里找对应的准备区数据
        List<ExperimentProcessSampleVo> experimentProcessSampleVos = experimentProcessSampleService.selectList(ExperimentProcessSampleSearchVo.builder()
                .experimentProcessId(experimentProcessId)
                .build());
        if (CollectionUtil.isEmpty(experimentProcessSampleVos)) {
            return null;
        }
        Long readyId = experimentProcessSampleVos.get(0).getReadyId();
        if (Objects.isNull(readyId)) {
            return null;
        }
        return this.selectVoById(readyId);
    }

    @Transactional(rollbackFor = Exception.class, value = "localTransactionManager")
    @Override
    public boolean saveDetail(ExperimentProcessSampleReadySaveOrUpdateOutVo experimentProcessSampleReadySaveOrUpdateOutVo) {
        ExperimentProcessSampleReady oldExperimentProcessSampleReady = this.selectById(experimentProcessSampleReadySaveOrUpdateOutVo.getId());
        AssertUtil.notNull(oldExperimentProcessSampleReady, "此样本准备流程不存在或者已被删除");
        AssertUtil.check(oldExperimentProcessSampleReady.getStatus() != AllExperimentationStepStatusEnum.UN_END.getCode().byteValue(), "此样本准备流程已完成，请勿重复提交");
        //样本准备记录id
        ExperimentProcessSampleReady experimentProcessSampleReady = new ExperimentProcessSampleReady();
        BeanUtils.copyProperties(experimentProcessSampleReadySaveOrUpdateOutVo, experimentProcessSampleReady);
        experimentProcessSampleReady.setStatus(AllExperimentationStepStatusEnum.END.getCode().byteValue());
        experimentProcessSampleReady.setEndTime(new Date());
        //先修改样本准备表数据
        this.updateByPrimaryKeySelective(experimentProcessSampleReady);

        List<ExperimentProcessSampleLog> experimentProcessSampleLogList = Lists.newArrayList();
        experimentProcessSampleReadySaveOrUpdateOutVo.getSamples().forEach(e -> {
            String zlxbbl = e.getZlxbbl();
//            AssertUtil.check(!NumberUtil.isInteger(zlxbbl), "肿瘤细胞比例只能为数字");
            ExperimentProcessSample experimentProcessSample = experimentProcessSampleService.selectById(e.getSampleId());
            AssertUtil.notNull(experimentProcessSample, "有样本不存在或者已被删除");
            ExperimentProcessSample updateParam = new ExperimentProcessSample();
            updateParam.setId(e.getSampleId());
            updateParam.setZlxbbl(zlxbbl);
            updateParam.setId(e.getSampleId());
            ExperimentTypeEnum experimentTypeEnum = ExperimentTypeEnum.getByCode(experimentProcessSample.getMainType().intValue());
            //样本的监测项目
            List<String> projectList = Arrays.asList(experimentProcessSample.getProject().split(","));
            //日志记录
            String op = "样本准备";
            assert experimentTypeEnum != null;
            switch (experimentTypeEnum) {
                case PCR:
                    AssertUtil.check(experimentProcessSample.getStatus() != PcrSampleStatusEnum.WAIT_ZB.getCode().byteValue(),
                            String.format("分子病理号号为%s的样本状态不允许进行样本准备", experimentProcessSample.getMoleculePathologyNumber()));
                    updateParam.setStatus(PcrSampleStatusEnum.YZB.getCode().byteValue());
                    if (projectList.contains(ExperimentTypeEnum.PCR.getProject().get(0)) || projectList.contains(ExperimentTypeEnum.PCR.getProject().get(1))
                            || projectList.contains(ExperimentTypeEnum.PCR.getProject().get(2)) || projectList.contains(ExperimentTypeEnum.PCR.getProject().get(5))) {
                        if (Integer.valueOf(zlxbbl) < commonConfig.getYbzbZlxbblPcrMin()) {
                            op = String.format("不合格，原因：%s", "样本准备中，肿瘤细胞比例未达标");
                            updateParam.setStatus(PcrSampleStatusEnum.BHG.getCode().byteValue());
                        }
                    }
                    break;
                case SANGER:
                    AssertUtil.check(experimentProcessSample.getStatus() != SangerSampleStatusEnum.WAIT_ZB.getCode().byteValue(),
                            String.format("分子病理号号为%s的样本状态不允许进行样本准备", experimentProcessSample.getMoleculePathologyNumber()));
                    updateParam.setStatus(SangerSampleStatusEnum.YZB.getCode().byteValue());
                    if (Integer.valueOf(zlxbbl) < commonConfig.getYbzbZlxbblSangerMin()) {
                        op = String.format("不合格，原因：%s", "样本准备中，肿瘤细胞比例未达标");
                        updateParam.setStatus(PcrSampleStatusEnum.BHG.getCode().byteValue());
                    }
                    break;
                case FISH:
                    AssertUtil.check(experimentProcessSample.getStatus() != ExperimentFishSampleStatusEnum.WAIT_ZB.getCode().byteValue(),
                            String.format("分子病理号号为%s的样本状态不允许进行样本准备", experimentProcessSample.getMoleculePathologyNumber()));
                    updateParam.setStatus(ExperimentFishSampleStatusEnum.YZB.getCode().byteValue());
                    break;
                case NGS:
                    AssertUtil.check(experimentProcessSample.getStatus() != NgsSampleStatusEnum.WAIT_ZB.getCode().byteValue(),
                            String.format("分子病理号号为%s的样本状态不允许进行样本准备", experimentProcessSample.getMoleculePathologyNumber()));
                    updateParam.setStatus(NgsSampleStatusEnum.YZB.getCode().byteValue());
                    if (Integer.valueOf(zlxbbl) < commonConfig.getYbzbZlxbblNgsMin()) {
                        op = String.format("不合格，原因：%s", "样本准备中，肿瘤细胞比例未达标");
                        updateParam.setStatus(PcrSampleStatusEnum.BHG.getCode().byteValue());
                    }
                    break;
                default:
                    break;
            }
            experimentProcessSampleService.updateByPrimaryKeySelective(updateParam);
            experimentProcessSampleLogList.add(ExperimentProcessSampleLog.builder()
                    .sampleId(e.getSampleId())
                    .mainType(experimentProcessSample.getMainType())
                    .op(op)
                    .opUser(CurrentUserHolder.getUser().getName())
                    .build());
        });
        experimentProcessSampleLogService.saveBatch(experimentProcessSampleLogList);
        return true;
    }

    @Transactional(rollbackFor = Exception.class, value = "localTransactionManager")
    @Override
    public boolean save(SampleReadySaveOrUpdateVo sampleReadySaveOrUpdateVo) {
        ExperimentProcessSampleReady pcr = new ExperimentProcessSampleReady();
        BeanUtils.copyProperties(sampleReadySaveOrUpdateVo, pcr);
        pcr.setStatus(AllExperimentationStepStatusEnum.UN_END.getCode().byteValue());
        Date now = new Date();
        String today = DateUtil.formatDate(now);
        pcr.setStartTime(now);
        //今天有几个实验了
        Integer count = this.count(ExperimentProcessSampleReadySearchVo.builder()
                .startDay(today)
                .build());
        String processNumber = String.format(number, DateUtil.format(now, "yyyyMMdd"), String.format("%02d", count + 1));
        //编号
        pcr.setProcessNumber(processNumber);
        Long readyId = this.insert(pcr);
        List<ExperimentProcessSampleLog> experimentProcessSampleLogList = Lists.newArrayList();
        sampleReadySaveOrUpdateVo.getSampleIds().forEach(e -> {
            ExperimentProcessSample experimentProcessSample = experimentProcessSampleService.selectById(e);
            AssertUtil.notNull(experimentProcessSample, "有样本不存在或者已被删除");
            ExperimentProcessSample updateParam = new ExperimentProcessSample();
            updateParam.setReadyId(readyId);
            updateParam.setId(e);
            ExperimentTypeEnum experimentTypeEnum = ExperimentTypeEnum.getByCode(experimentProcessSample.getMainType().intValue());
            assert experimentTypeEnum != null;
            switch (experimentTypeEnum) {
                case PCR:
                    AssertUtil.check(experimentProcessSample.getStatus() != PcrSampleStatusEnum.NEW.getCode().byteValue(),
                            String.format("分子病理号号为%s的样本状态不允许进入样本准备区", experimentProcessSample.getMoleculePathologyNumber()));
                    updateParam.setStatus(PcrSampleStatusEnum.WAIT_ZB.getCode().byteValue());
                    break;
                case SANGER:
                    AssertUtil.check(experimentProcessSample.getStatus() != SangerSampleStatusEnum.NEW.getCode().byteValue(),
                            String.format("分子病理号号为%s的样本状态不允许进入样本准备区", experimentProcessSample.getMoleculePathologyNumber()));
                    updateParam.setStatus(SangerSampleStatusEnum.WAIT_ZB.getCode().byteValue());
                    break;
                case FISH:
                    AssertUtil.check(experimentProcessSample.getStatus() != ExperimentFishSampleStatusEnum.NEW.getCode().byteValue(),
                            String.format("分子病理号号为%s的样本状态不允许进入样本准备区", experimentProcessSample.getMoleculePathologyNumber()));
                    updateParam.setStatus(ExperimentFishSampleStatusEnum.WAIT_ZB.getCode().byteValue());
                    break;
                case NGS:
                    AssertUtil.check(experimentProcessSample.getStatus() != NgsSampleStatusEnum.NEW.getCode().byteValue(),
                            String.format("分子病理号号为%s的样本状态不允许进入样本准备区", experimentProcessSample.getMoleculePathologyNumber()));
                    updateParam.setStatus(NgsSampleStatusEnum.WAIT_ZB.getCode().byteValue());
                    break;
                default:
                    break;
            }
            experimentProcessSampleService.updateByPrimaryKeySelective(updateParam);
            experimentProcessSampleLogList.add(ExperimentProcessSampleLog.builder()
                    .sampleId(e)
                    .mainType(experimentProcessSample.getMainType())
                    .op("待样本准备")
                    .opUser(CurrentUserHolder.getUser().getName())
                    .build());
        });
        return true;
    }

}